package com.map.components.https;

import com.map.core.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.CookieStore;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
public class SSLClient {

    public static final ResponseEntity post(final RequestEntity requestEntity) {
        //设置cookie stroe生成 httpClient
        CookieStore cookieStore = new BasicCookieStore();
        CloseableHttpClient httpClient = createSSLClientDefault().setDefaultCookieStore(cookieStore).build();

        HttpPost post = new HttpPost(requestEntity.getUrl());
        ResponseEntity responseEntity = new ResponseEntity();
        CloseableHttpResponse response = null;

        //设置请求头
        Map<String, String> headers = requestEntity.getAllHeaders();
        if (null != headers && !headers.isEmpty()) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                post.addHeader(new BasicHeader(entry.getKey(), entry.getValue()));
            }
        }
        //设置请求参数
        Map<String, String> params = requestEntity.getAllParams();
        if (null != params && !params.isEmpty()) {
            List nvpList = new ArrayList<NameValuePair>();
            for (Map.Entry<String, String> entry : params.entrySet()) {
                NameValuePair nvp = new BasicNameValuePair(entry.getKey(), entry.getValue());
                ((ArrayList) nvpList).add(nvp);
            }
            post.setEntity(new UrlEncodedFormEntity(nvpList, Charset.forName("UTF-8")));
        }

        try {
            response = httpClient.execute(post);
            //处理响应
            responseEntity.setAllHeaders(response.getAllHeaders());
            Integer status = response.getStatusLine().getStatusCode();
            responseEntity.setStatus(status);

            if (status == 200 || status == 302) {
                //获得Cookie
                getSetCookie(cookieStore, responseEntity);

                HttpEntity entity = response.getEntity();
                if (null != entity) {
                    String result = EntityUtils.toString(entity, "UTF-8");
                    responseEntity.setResult(result);
                }
            } else {
                log.error("https POST method request to :" + requestEntity.getUrl() + "is error. the response status code is " + response.getStatusLine().getStatusCode());
            }
        } catch (IOException ex) {
            log.error("" + ex);
        } finally {
            if (null != response) {
                try {
                    EntityUtils.consume(response.getEntity());
                } catch (IOException ex) {
                    log.error("" + ex);
                }
            }
        }

        return responseEntity;
    }


    public static final ResponseEntity get(final RequestEntity requestEntity) {
        //设置cookie stroe生成 httpClient
        CookieStore cookieStore = new BasicCookieStore();
        CloseableHttpClient httpClient = createSSLClientDefault().setDefaultCookieStore(cookieStore).build();

        CloseableHttpResponse response = null;
        ResponseEntity responseEntity = new ResponseEntity();
        StringBuilder sb = new StringBuilder();

        //设置请求参数
        Map<String, String> params = requestEntity.getAllParams();
        if (null != params && !params.isEmpty()) {
            int i = 0;
            for (String key : params.keySet()) {
                if (i == 0) {
                    sb.append("?");
                } else {
                    sb.append("&");
                }
                sb.append(key).append("=").append(params.get(key));
                i++;
            }
        }

        HttpGet get = new HttpGet(requestEntity.getUrl() + sb.toString());
        //设置请求头
        Map<String, String> headers = requestEntity.getAllHeaders();
        if (null != headers && !headers.isEmpty()) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                get.addHeader(new BasicHeader(entry.getKey(), entry.getValue()));
            }
        }

        String result = "";
        try {
            response = httpClient.execute(get);
            //处理响应
            responseEntity.setAllHeaders(response.getAllHeaders());
            Integer status = response.getStatusLine().getStatusCode();
            responseEntity.setStatus(status);

            if (status == 200 || status == 302) {
                //获得Cookie
                getSetCookie(cookieStore, responseEntity);
                HttpEntity entity = response.getEntity();
                if (null != entity) {
                    result = EntityUtils.toString(entity, "UTF-8");
                    responseEntity.setResult(result);
                }
            } else {
                log.error("https GET method request to :" + requestEntity.getUrl() + "is error. the response status code is " + response.getStatusLine().getStatusCode());
            }
        } catch (IOException ex) {
            log.error("" + ex);
        } finally {
            if (null != response) {
                try {
                    EntityUtils.consume(response.getEntity());
                } catch (IOException ex) {
                    log.error("" + ex);
                }
            }
        }

        return responseEntity;
    }

    private static void getSetCookie(CookieStore cookieStore, ResponseEntity responseEntity) {
        String header = responseEntity.getHeader("Set-Cookie");
        if(!StringUtils.isNullOrEmptyStr(header)) {
            responseEntity.setSetCookie(header);
        } else {
            List<Cookie> cookies = cookieStore.getCookies();
            for (Cookie cookie : cookies) {

                if ("Set-Cookie".equals(cookie.getName())) {
                    responseEntity.setSetCookie(cookie.getValue());
                }
            }
        }
    }

    private static HttpClientBuilder createSSLClientDefault() {

        SSLContext sslContext;
        try {
            sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
                //信任所有
                @Override
                public boolean isTrusted(X509Certificate[] xcs, String string) {
                    return true;
                }
            }).build();

            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    // ip address of the service URL(like.23.28.244.244)
                    if (hostname.equals("172.18.100.5"))
                        return true;
                    return false;
                }
            });



            return HttpClients.custom().setSSLSocketFactory(sslsf);
        } catch (KeyStoreException ex) {
            log.error("creat SSL Connection for https failed," + ex);
        } catch (NoSuchAlgorithmException ex) {
            log.error("creat SSL Connection for https failed," + ex);
        } catch (KeyManagementException ex) {
            log.error("creat SSL Connection for https failed," + ex);
        }

        return HttpClientBuilder.create();
    }

}
